from mg_app_framework import get_logger
from datetime import datetime
from common.basic_mongo import get_retrospect_collection, get_batch_code_config_collection, \
    get_new_batch_code_config_collection
from common.basic_redis import build_mg_redis_key, get_redis_conn
from common.constant import RetrospectType, WorkOrderConfig, CodeTypeEnum, MaterialConfig

WORK_ORDER_KEY_EX_TIME = 3600 * 24 * 3  # 设置工单key的过期时间是3天, 产出和投入时间相隔3天够了(过期了也可以在mongo中兜底获取)

__all__ = ["get_material_code", "get_work_order_code", "get_unique_id", "get_batch_code_material_code_map"]


def get_unique_id() -> str:
    """
    获取输入时间的开始时间
    :return:
    """
    now_time_stamp = datetime.now().strftime("%Y%m%d%H%M%S.%f")
    return now_time_stamp.replace(".", "")


async def get_batch_code_material_code_map(code_list: list) -> dict:
    """
    原料码值与物料的映射关系
    :param code_list:
    :return:
    """
    collection = get_batch_code_config_collection()
    query_filter = {"qr_code": {"$in": code_list}}
    result = {}
    async for rec in collection.find(query_filter):
        qr_code = rec["qr_code"]
        material_code = rec["material_code"]
        result.update({qr_code: material_code})

    return result


async def get_new_batch_code_material_code_map(code_list: list) -> dict:
    """
    原料码值与物料的映射关系
    :param code_list:
    :return:
    """
    collection = get_new_batch_code_config_collection()
    query_filter = {"qr_code": {"$in": code_list}}
    result = {}
    async for rec in collection.find(query_filter):
        qr_code = rec["qr_code"]
        material_code = rec["material_code"]
        result.update({qr_code: material_code})

    return result


async def get_material_code(qr_code: str, op_type: str, work_order_config: WorkOrderConfig) -> str:
    """

    :param qr_code:
    :param op_type:
    :param work_order_config:
    :return:
    """
    # seq1: 在追溯表中获取相关的物料编码
    retrospect_handler = get_retrospect_collection()
    recently_doc = await retrospect_handler.find_one(
        {
            "qr_code": qr_code,
            "is_delete": False,
        },
        {"_id": 0, "material_code": 1},
        sort=[("op_time", -1)],
    )
    if recently_doc:
        return recently_doc["material_code"]

    # seq2: 在原材俩批次码导入表中获取
    # 原料码值与物料的映射关系
    qr_code_material_code_map: dict = await get_batch_code_material_code_map(code_list=[qr_code])
    material_code = qr_code_material_code_map.get(qr_code, "")
    if material_code:
        return material_code
    # 卷绕工序的投入批次码信息由033出站时直接写入一张后台表，其功能和原材俩批次码导入表一致。
    # 由于原材俩批次码导入表仅维护导入的信息，所以维护了这样一张后台表，此处卷绕工序的追溯数据获取无聊时，可以在后台表查询
    qr_code_material_code_map_new: dict = await get_new_batch_code_material_code_map(code_list=[qr_code])
    material_code = qr_code_material_code_map_new.get(qr_code, "")
    if material_code:
        return material_code
    return ""


def make_work_order_id(workorder_code: str) -> str:
    """
    获取工单的子工单信息
    :param workorder_code:
    :return:
    """
    return f"{workorder_code}~{get_unique_id()}"


async def get_work_order_code(
        qr_code: str, op_type: str, work_order_config: WorkOrderConfig, material_config: MaterialConfig
) -> str:
    """
    获取唯一的工单编码。根据二维码、工单编码和操作类型，决定是从 Redis 获取或生成新的工单编码。

    :param material_config:
    :param work_order_config:
    :param qr_code: 二维码
    :param op_type: 操作类型
    :return: 返回唯一的工单编码
    """
    if material_config.code_type == CodeTypeEnum.batch_code:
        # 无法根据投入的批次码找到子工单
        return ""
    rd_conn = get_redis_conn()
    work_order_key = build_mg_redis_key(f"unique_work_order_id:{work_order_config.procedure_code}-{qr_code}",
                                        app_module_name="work_order_key")

    unique_work_order_code = await rd_conn.get(work_order_key)
    if unique_work_order_code:
        return unique_work_order_code

    if op_type == RetrospectType.PRODUCT_IN:
        unique_work_order_code = make_work_order_id(work_order_config.workorder_code)
        await rd_conn.set(work_order_key, unique_work_order_code, nx=True, ex=WORK_ORDER_KEY_EX_TIME)
        return unique_work_order_code
    elif op_type == RetrospectType.PRODUCT_OUT:
        # 产出的时候，理论不会重复调用
        get_logger().info(f"get_work_order_code with time expire, 二维码:{qr_code}")
        retrospect_handler = get_retrospect_collection()
        recently_doc = await retrospect_handler.find_one(
            {
                "qr_code": qr_code,
                "op_type": RetrospectType.PRODUCT_IN,
                "procedure_code": work_order_config.procedure_code,
                "is_delete": False,
            },
            {"_id": 0, "workorder_code": 1},
            sort=[("op_time", -1)],
        ) or {}
        unique_work_order_code = recently_doc.get("workorder_code", "")
        return unique_work_order_code

    return ""
